{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<div class=\"contentcontainer med left\" style=\"margin-left: -50px;\">\n",
    "<dl class=\"dl-horizontal\">\n",
    "  <dt>Title</dt> <dd> VectorField Element</dd>\n",
    "  <dt>Dependencies</dt> <dd>Bokeh</dd>\n",
    "  <dt>Backends</dt> <dd><a href='./VectorField.ipynb'>Bokeh</a></dd> <dd><a href='../matplotlib/VectorField.ipynb'>Matplotlib</a></dd>\n",
    "</dl>\n",
    "</div>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import holoviews as hv\n",
    "hv.extension('bokeh')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "A ``VectorField`` plot displays velocity vectors as arrows at ``x`` and ``y`` positions with angle and magnitude components (or alternatively ``U``, ``V`` components). The element accepts the usual columnar format passing the ``(x, y, angles, magnitudes)`` components as a tuple, but also handles 2D arrays when supplied as a list instead:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%opts VectorField [size_index=3]\n",
    "x,y  = np.mgrid[-10:10,-10:10] * 0.25\n",
    "sine_rings  = np.sin(x**2+y**2)*np.pi+np.pi\n",
    "exp_falloff = 1/np.exp((x**2+y**2)/8)\n",
    "\n",
    "vector_data = [x,y,sine_rings, exp_falloff]\n",
    "hv.VectorField(vector_data)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "As you can see above, here the *x* and *y* positions are chosen to make a regular grid. The arrow angles follow a sinsoidal ring pattern, and the arrow lengths fall off exponentially from the center, so this plot has four dimensions of data (direction and length for each *x,y* position).\n",
    "\n",
    "Using the ``%%opts`` cell-magic, we can also use color as a redundant indicator to the direction or magnitude:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%opts VectorField [size_index=3] VectorField.A [color_index=2] VectorField.M [color_index=3]\n",
    "hv.VectorField(vector_data, group='A') + hv.VectorField(vector_data, group='M')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "By default the arrows are rescaled to the minimum distance between individual arrows, to disable this rescaling set ``rescale=False`` and adjust the ``scale`` manually (smaller values result in larger arrows). This allows fixed scaling even when plotting arrows in an animation. Here we will vary the arrow angle with a Phase dimension and also add this angle to the magnitude data, showing the arrow angles and magnitudes varying. Due to the fixed scaling we can make out the differences across frames:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%opts VectorField [color_index=2 size_index=3 rescale_lengths=False] (scale=4)\n",
    "hv.HoloMap({phase: hv.VectorField([x, y,(vector_data[2]+phase)%np.pi*2, vector_data[3]+np.abs(phase)])\n",
    "            for phase in np.linspace(-np.pi,np.pi,5)}, kdims=['Phase'])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Vectors are also often expressed through U and V components we can easily transform these to a magnitude and angle:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "xs, ys = np.arange(0, 2 * np.pi, .2), np.arange(0, 2 * np.pi, .2)\n",
    "X, Y = np.meshgrid(xs, ys)\n",
    "U = np.cos(X)\n",
    "V = np.sin(Y)\n",
    "\n",
    "# Convert U, V to magnitude and angle\n",
    "mag = np.sqrt(U**2 + V**2)\n",
    "angle = (np.pi/2.) - np.arctan2(U/mag, V/mag)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "``VectorField`` also allows defining the ``pivot`` point of the vectors. We can for instance define ``pivot='tip'`` to pivot around the tip of the arrow. To make this clearer we will mark the pivot points:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%opts VectorField [width=500 color_index=3 size_index=3 pivot='tip'] (cmap='fire' scale=0.8) Points (color='black' size=1)\n",
    "hv.VectorField((xs, ys, angle, mag)) * hv.Points((X.flat, Y.flat))"
   ]
  }
 ],
 "metadata": {
  "language_info": {
   "name": "python",
   "pygments_lexer": "ipython3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
